﻿//http://www.codeproject.com/Articles/28860/XAML-polygon-transformation-tool
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using BenTools.Mathematics;

namespace WpfVoronoiDllTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
       // ClGT Gt = new ClGT();
        int precision = 2;
        VoronoiGraph VorGraph;
        List<BenTools.Mathematics.Vector> SeedsVectors;
        // For Binding point to grid
        //ObservableCollection<Point> OclSeedsPoint;
        OclPointData OclSeedsPoint;
        // bool IsMouseDown ;
        // To generate Polygon topology
        List<CLEdgeData> LEdgeData;
        List<CLPolygon> LPolygon;
        //double[,] SeedPoints;
        int pointcount;
        // For coloring of WPF shapes.

        private Brush[] shapeBrushes = new Brush[]{
            
            Brushes.BlueViolet,Brushes.Crimson,Brushes.DarkKhaki,Brushes.DarkSeaGreen,
             Brushes.ForestGreen, Brushes.Indigo, Brushes.LemonChiffon,
                Brushes.Navy,  Brushes.LightSlateGray,  Brushes.Olive,Brushes.RoyalBlue, Brushes.Violet ,
            
        };
        //Last clicked tool
        private enum EClickedTool
        {
            Mouse, Point, MirrorH, MirrorV, MirrorFH, MirrorFV,Magnet
        }

        private EClickedTool Tool = EClickedTool.Mouse;
        
        private Random randBrush = new Random(379013);
        private Random rand = new Random();

        int DrawHeight, DrawWidth;
        double margin;
        TranslateTransform panTransform = new TranslateTransform();

        public MainWindow()
        {
            InitializeComponent();
            //SeedPoints list
            SeedsVectors = new List<BenTools.Mathematics.Vector>();
            //OclSeedsPoint = new ObservableCollection<Point>();
            OclSeedsPoint = new OclPointData();
            // Bind the panel with the Ocl
            SeedPanel.DataContext = OclSeedsPoint;
            // Edge and SeedPoint Id to reconstruct polygons
            LEdgeData = new List<CLEdgeData>();
            LPolygon = new List<CLPolygon>();           
            pointcount = 0;
            DrawHeight = 250;
            DrawWidth = 450;
            margin = 1.1;
            panTransform.X = 50;
            panTransform.Y = 50;

            //canvas1.RenderTransform = new TranslateTransform(100, 100);
        }

        private void button_seed_Click(object sender, RoutedEventArgs e)
        {
            OclSeedsPoint.Clear();
            OclSeedsPoint.Random(DrawWidth * margin, DrawHeight * margin);
        }
        private void button_brick_Click(object sender, RoutedEventArgs e)
        {
            OclSeedsPoint.Clear();
            OclSeedsPoint.Brick(DrawWidth * margin, DrawHeight * margin);
        }

        private void button_honey_Click(object sender, RoutedEventArgs e)
        {
            OclSeedsPoint.Clear();
            OclSeedsPoint.Honey(DrawWidth * margin, DrawHeight * margin);            
        }
        private void button_circular_seed_Click(object sender, RoutedEventArgs e)
        {            
            OclSeedsPoint.Clear();
            OclSeedsPoint.Circular(DrawWidth, DrawHeight);
        }

        private void button_spiral_seed_Click(object sender, RoutedEventArgs e)
        {
            OclSeedsPoint.Clear();
            OclSeedsPoint.Spiral(DrawWidth, DrawHeight);
        }
        private void button_spiral_double_Click(object sender, RoutedEventArgs e)
        {
            OclSeedsPoint.Clear();
            OclSeedsPoint.SpiralDouble(DrawWidth, DrawHeight);
        }
        // Apply the selected tool in Click mouse position          
        private void SeedPanel_MouseDown(object sender, MouseButtonEventArgs e)
        {
            //Debug.WriteLine("MouseDown, X:" + e.GetPosition(canvas1).X.ToString() + " Y:" + e.GetPosition(canvas1).Y.ToString());            

            
            switch (Tool)
            {
                case EClickedTool.Point:
                    {
                        DrawPoint(e.GetPosition(SeedPanel).X, e.GetPosition(SeedPanel).Y, Brushes.Yellow);
                        OclSeedsPoint.Add(new InpcPointData(e.GetPosition(SeedPanel).X, e.GetPosition(SeedPanel).Y));                      
                        break;
                    }
                case EClickedTool.Magnet:
                    { ; break; }
                case EClickedTool.MirrorH:
                    {
                        OclSeedsPoint.MirrorH(DrawWidth * margin, DrawHeight * margin, e.GetPosition(SeedPanel).X, e.GetPosition(SeedPanel).Y);
                        //SeedPanel.DataContext = OclSeedsPoint;
                            Debug.WriteLine("Mirror H");
                        ; break; }
                case EClickedTool.MirrorV:
                    {
                        OclSeedsPoint.MirrorV(DrawWidth * margin, DrawHeight * margin, e.GetPosition(SeedPanel).X, e.GetPosition(SeedPanel).Y);
                        //SeedPanel.DataContext = OclSeedsPoint;
                        Debug.WriteLine("Mirror V");
                        ; break;
                    }
                case EClickedTool.MirrorFV:
                    {
                        OclSeedsPoint.MirrorFlipV(DrawWidth * margin, DrawHeight * margin, e.GetPosition(SeedPanel).X, e.GetPosition(SeedPanel).Y);
                        //SeedPanel.DataContext = OclSeedsPoint;
                        Debug.WriteLine("Mirror Flip V");
                        ; break;
                    }
                case EClickedTool.MirrorFH:
                    {
                        OclSeedsPoint.MirrorFlipH(DrawWidth * margin, DrawHeight * margin, e.GetPosition(SeedPanel).X, e.GetPosition(SeedPanel).Y);
                        //SeedPanel.DataContext = OclSeedsPoint;
                        Debug.WriteLine("Mirror Flip H");
                        ; break;
                    }
            }

            Tool = EClickedTool.Mouse;// do nothing





        }

        private void button_voronoi_Click(object sender, RoutedEventArgs e)
        {
            if (OclSeedsPoint.Count < 4) return;
            // Reset the Voronoi Canvas
            this.canvas1.Children.Clear();
            // Load the SeedsVectors from the OclSeedsPoint
            SeedsVectors.Clear();
            pointcount =0;
            foreach (InpcPointData iPd in OclSeedsPoint)
            {
                //SeedsVectors.Add(new BenTools.Mathematics.Vector(iPd.X,iPd.Y, pointcount));
                SeedsVectors.Add(new BenTools.Mathematics.Vector(iPd.X, iPd.Y));
                pointcount++;
                DrawPoint(iPd.X,iPd.Y, Brushes.ForestGreen); 
            }

            //Compute the Voronoi Graph
            VorGraph = BenTools.Mathematics.Fortune.ComputeVoronoiGraph(SeedsVectors);

            // Draw Voronoi  Vertizes
             /* Debug.WriteLine("VorGraph.Vertizes:" + VorGraph.Vertizes.Count.ToString());
            foreach (BenTools.Mathematics.Vector VertPoint in VorGraph.Vertizes)
            {
                  DrawPoint(VertPoint, Brushes.Red);            
            }*/

            //-----------------------------------
            // Show the Edges of Voronoi Graph
            foreach (BenTools.Mathematics.VoronoiEdge VorEdge in VorGraph.Edges)
            {
               Line line = new Line();
                line.Fill = Brushes.Blue;
                line.StrokeThickness = 1;
                line.Stroke = Brushes.Blue;

                try
                {
                    if (!VorEdge.IsPartlyInfinite)
                    {
                        // Load edges
                        //Debug.WriteLine("IsPartlyInfinite");
                        /*
                        line.X1 = VorEdge.VVertexA[0] = Math.Round(VorEdge.VVertexA[0], precision);
                        line.Y1 = VorEdge.VVertexA[1] = Math.Round(VorEdge.VVertexA[1], precision);

                        line.X2 = VorEdge.VVertexB[0] = Math.Round(VorEdge.VVertexB[0], precision);
                        line.Y2 = VorEdge.VVertexB[1] = Math.Round(VorEdge.VVertexB[1], precision);
                        */                        
                        
                        line.X1 = VorEdge.VVertexA[0] ;line.Y1 = VorEdge.VVertexA[1] ;                        
                        line.X2 = VorEdge.VVertexB[0] ;line.Y2 = VorEdge.VVertexB[1] ;

                    }
                    else
                    {
                        // draw rays going out of the viewing area
                        if (!VorEdge.IsInfinite)
                        {
                            // if B is infinite
                            Debug.WriteLine(" B is infinite");
                            BenTools.Mathematics.Vector VertexB2 = VorEdge.FixedPoint + VorEdge.DirectionVector *( DrawHeight /2); // VorEdge.VVertexA.SquaredLength;
                            //VertexB2 = Gt.BorderIntersection(VorEdge.FixedPoint, VertexB2, DrawWidth , DrawHeight);                                                    
                            //A
                            line.X1 = VorEdge.VVertexA[0]; // = Math.Round(VorEdge.VVertexA[0], precision);
                            line.Y1 = VorEdge.VVertexA[1]; // = Math.Round(VorEdge.VVertexA[1], precision);
                            //B                         
                            //line.X2 = VertexB2[0];line.Y2 = VertexB2[1];
                            line.X2 = VorEdge.VVertexB[0] = VertexB2[0];
                            line.Y2 = VorEdge.VVertexB[1] = VertexB2[1];
                           
                        }
                        else
                        {
                            // if A and B are infinite (for 2 points)
                            Debug.WriteLine("A and B are infinite");
                            BenTools.Mathematics.Vector VertexA = VorEdge.FixedPoint -
                                              VorEdge.DirectionVector * ( DrawHeight /2);
                            BenTools.Mathematics.Vector VertexB = VorEdge.FixedPoint +
                                              VorEdge.DirectionVector * ( DrawHeight /2);
                            line.X1 = VertexA[0];line.Y1 = VertexA[1];
                            line.X2 = VertexB[0];line.Y2 = VertexB[1];
                        }
                    }
                }
                catch (Exception e2)
                {
                    Debug.WriteLine("Exception :" + e2.Message);
                }

                // Cut infinite lines
                // Comparar el segmento y el recuadro
                // Two point outside then dischargue the edge
                if (Gt.OutsideBound(VorEdge.VVertexA, DrawWidth, DrawHeight) && Gt.OutsideBound(VorEdge.VVertexB, DrawWidth, DrawHeight))
                { continue; }


                if (Gt.OutsideBound(VorEdge.VVertexA, DrawWidth, DrawHeight))
                {  //A outside B inside
                    BenTools.Mathematics.Vector A2 = Gt.BorderIntersection(VorEdge.VVertexA, VorEdge.VVertexB, DrawWidth, DrawHeight);                  
                    line.X1 = A2[0]; line.Y1 = A2[1];
                    //DrawPoint(VorEdge.VVertexA, Brushes.Yellow);                                 
                    //DrawPoint(VorEdge.VVertexB, Brushes.HotPink);
                    //DrawPoint(A2, Brushes.Black);
                }
                else
                {
                    // Can be A and B inside
                    // Check B
                    if (Gt.OutsideBound(VorEdge.VVertexB, DrawWidth, DrawHeight))
                    { //A inside B Outside
                        BenTools.Mathematics.Vector B2 = Gt.BorderIntersection(VorEdge.VVertexA, VorEdge.VVertexB, DrawWidth, DrawHeight);                       
                        line.X2 = B2[0];line.Y2 = B2[1];                        
                      // DrawPoint(VorEdge.VVertexA, Brushes.Blue);
                       //DrawPoint(VorEdge.VVertexB, Brushes.Red);
                       //DrawPoint( B2, Brushes.Green);
                    }
                }
                //
                 


                //DrawPoint(VorEdge.FixedPoint, Brushes.Blue);
                //BenTools.Mathematics.Vector VCenter = new BenTools.Mathematics.Vector(100, 100);
                //DrawPoint(VCenter+VorEdge.DirectionVector * 50, Brushes.Red);
                
                //DrawPoint(VorEdge.VVertexA, Brushes.Yellow);                
               
                //VorEdge.VVertexB[0] == double.PositiveInfinity
                //Debug.WriteLine("A X1:" + line.X1.ToString() + " Y1:" + line.Y1.ToString());
                
                //Debug.WriteLine("B X2:" + line.X2.ToString() + " Y2:" + line.Y1.ToString());

                //line.RenderTransform = new TranslateTransform(100, 100);

                line.RenderTransform = panTransform;
                canvas1.Children.Add(line);
                // Add Rectangle with DrawLimits
                
                Rectangle rectangle = new Rectangle();
                rectangle.Stroke = Brushes.Gray;
                rectangle.StrokeThickness =0.5;
                rectangle.Width = DrawWidth;
                rectangle.Height = DrawHeight;
                rectangle.RenderTransform = panTransform;
                 canvas1.Children.Add(rectangle);
                

            }
        }
        //-------------------------------------------------------------
        // Build the Polygon topology from the edges of the asosiated seeds
        //-------------------------------------------------------------
        
        private void button_polygon_Click(object sender, RoutedEventArgs e)
        {
            if (VorGraph == null) return;

            canvas1.Children.Clear();
            //canvas1.Children.OfType<Polygon>().ToList().Clear();//dont work            
            LEdgeData.Clear();
            LPolygon.Clear();
 
            //if (VorGraph.Edges.Count < 1) return;

            // Walk the Edges list :VorGraph.Edges
            // Get the 2 more near Points: SeedsVectors.OrderBy(vc => Gt.VectorDistance(vc, VertexMiddle))
            // Store the Points and the Edge in list: LEdgeData
            // Reconstruct every polygon in list: LPolygon
            
            foreach (BenTools.Mathematics.VoronoiEdge VorEdge in VorGraph.Edges)
            {

                double X1 = 0, Y1 = 0, X2 = 0, Y2 = 0;

                try
                {
                    if (!VorEdge.IsPartlyInfinite)
                    {
                        // draw edges
                        //Debug.WriteLine("IsPartlyInfinite");
                        X1 = Math.Round(VorEdge.VVertexA[0],precision);
                        Y1 = Math.Round(VorEdge.VVertexA[1], precision);

                        X2 = Math.Round(VorEdge.VVertexB[0], precision);
                        Y2 = Math.Round(VorEdge.VVertexB[1], precision);
                    }
                    else
                    {
                        // draw rays going out of the viewing area
                        if (!VorEdge.IsInfinite)
                        {
                            // if B is infinite
                            //Debug.WriteLine(" B is infinite");
                            BenTools.Mathematics.Vector B2 = VorEdge.FixedPoint + VorEdge.DirectionVector * DrawHeight; // VorEdge.VVertexA.SquaredLength;
                            //A
                            X1 = Math.Round(VorEdge.VVertexA[0], precision);
                            Y1 = Math.Round(VorEdge.VVertexA[1], precision);

                            //B
                            X2 = Math.Round(B2[0], precision);
                            Y2 = Math.Round(B2[1], precision);

                        
                        }
                        else
                        {   // Only for 2 points (never happen)
                            // if A and B are infinite (for 2 points)
                            //Debug.WriteLine("A and B are infinite");
                            BenTools.Mathematics.Vector VVertexA = VorEdge.FixedPoint -
                                              VorEdge.DirectionVector * DrawHeight;
                            BenTools.Mathematics.Vector VVertexB = VorEdge.FixedPoint +
                                              VorEdge.DirectionVector * DrawHeight;
                            X1 = VVertexA[0];
                            Y1 = VVertexA[1];

                            X2 = VVertexB[0];
                            Y2 = VVertexB[1];
                        }
                    }
                }//try
                catch (Exception e2)
                {
                    Debug.WriteLine("Exception :" + e2.Message);
                }
                //------------------------------------------------
                // Check for point outside bounds
                // Exlude infinite lines A and B outside
                // Comparar el segmento y el recuadro
                // Two point outside then dischargue the edge
                if (Gt.OutsideBound(VorEdge.VVertexA, DrawWidth, DrawHeight) && Gt.OutsideBound(VorEdge.VVertexB, DrawWidth, DrawHeight))
                { continue; }


                if (Gt.OutsideBound(VorEdge.VVertexA, DrawWidth, DrawHeight))
                {  //A outside B inside
                    BenTools.Mathematics.Vector AI = Gt.BorderIntersection(VorEdge.VVertexA, VorEdge.VVertexB, DrawWidth, DrawHeight);
                    X1 = Math.Round(AI[0], precision); Y1 = Math.Round(AI[1], precision);                }
                else
                {
                    // Can be A and B inside
                    // Check B                   
                    if (Gt.OutsideBound(VorEdge.VVertexB, DrawWidth, DrawHeight))
                    { //A inside B Outside
                        BenTools.Mathematics.Vector Bo = VorEdge.FixedPoint + VorEdge.DirectionVector * DrawHeight;                           
                        BenTools.Mathematics.Vector BI = Gt.BorderIntersection(VorEdge.VVertexA, Bo, DrawWidth, DrawHeight);
                        X2 = BI[0]; Y2 = BI[1];                        
                    }
                }


                //DrawPoint(VertexMiddle, Brushes.Red);              

                //Get Middle Point of Edge
                   BenTools.Mathematics.Vector VertexMiddle = Gt.HalfPointOfLine(X1, Y1, X2, Y2);                
                //-------------------------------------------
                // Get the 2 more near points and store in:LEdgeData
                
                int i = 1;
                foreach (BenTools.Mathematics.Vector iSVp in SeedsVectors.OrderBy(vc => Gt.VectorDistance(vc, VertexMiddle)))
                {                    
                    // Store the point ID and their edge
                   LEdgeData.Add(new CLEdgeData(SeedsVectors.IndexOf(iSVp), X1, Y1, X2, Y2));                    
                   // LEdgeData.Add(new CLEdgeData((int)iSVp[2], X1, Y1, X2, Y2));                    
                    i++;
                    if (i > 2) break;//Only two points
                }
            }

            
            // Fill LPolygon with null data to work with [Pntid]
            
            for (int i = 0; i < pointcount + 1; i++)
            {
                LPolygon.Add(new CLPolygon());
            }

            // Store the points of every edge 
            // Load the point edges in their respetive Point
            foreach (CLEdgeData iEdegeData in LEdgeData.OrderBy(ob => ob.PntId))
            {
                LPolygon[iEdegeData.PntId].PolPoints.Add(iEdegeData.A);
                LPolygon[iEdegeData.PntId].PolPoints.Add(iEdegeData.B);
            }


            // Draw every Polygon in LPolygon
            foreach (CLPolygon iPolygon in LPolygon)
            {
                
                //Sort the points                 
                iPolygon.PolPoints.Sort((a, b) => Gt.Angle(a, iPolygon.Center()).CompareTo(Gt.Angle(b, iPolygon.Center())));
                //iPolygon.PolPoints = iPolygon.PolPoints.OrderBy(pt => Gt.Angle(pt, iPolygon.Center())).ToList();
                // Eliminate duplicates                
                iPolygon.PolPoints = iPolygon.PolPoints.Distinct().ToList();                                
                // Reduce the data  geometry
                iPolygon.PolygonScale(0.85);
                //---------------------------
                // Create a Polygon shape
                Polygon polygon = new Polygon();
                polygon.Stroke = Brushes.Black;
                polygon.Fill = GetRandomShapeBrush();
                polygon.StrokeThickness = 1;
                polygon.Points = new PointCollection(iPolygon.PolPoints); 
               
                // Don work properly
                //polygon.RenderTransformOrigin = new Point(0.5, 0.5);
                //polygon.RenderTransform = new ScaleTransform(0.70, 0.70);
                //--------------
                // Work Ok
                //polygon.RenderTransform = new ScaleTransform(0.80, 0.80, iPolygon.Center().X, iPolygon.Center().Y);              
           
                // Evento On Click Scale ++ or --
                polygon.MouseLeftButtonDown += new MouseButtonEventHandler(polygon_MouseLeftButtonDown);
                polygon.MouseRightButtonDown += new MouseButtonEventHandler(polygon_MouseRightButtonDown);                
                polygon.RenderTransform = panTransform;
                canvas1.Children.Add(polygon);
            }




        }


        void polygon_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {           
            Polygon polygon = sender as Polygon;
            polygon.Points = Gt.PolygonScale(polygon.Points , 0.95);
            //polygon.RenderTransform = new ScaleTransform(0.90, 0.90,Gt.PolygonCenter(polygon.Points).X,Gt.PolygonCenter(polygon.Points ).Y);
        }

        void polygon_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            Polygon polygon = sender as Polygon;
            polygon.Points = Gt.PolygonScale(polygon.Points , 1.05);
            //polygon.RenderTransform = new ScaleTransform(1.1, 1.1, Gt.PolygonCenter(polygon.Points).X, Gt.PolygonCenter(polygon.Points).Y);
        }


       
      
            void DrawPoint(BenTools.Mathematics.Vector vector, Brush brush)
            {
                DrawPoint(vector[0], vector[1], brush);
            }

            void DrawPoint(Point Pnt, Brush brush)
            {
                DrawPoint(Pnt.X, Pnt.Y, brush);
            }

            void DrawPoint(double x, double y, Brush brush)
            {
                Ellipse myEllipse = new Ellipse();
                ///mySolidColorBrush.Color = Color.FromArgb(255, 255, 255, 0);
                myEllipse.Fill = brush;// Brushes.Green; //.mySolidColorBrush;
                myEllipse.StrokeThickness = 0;
                myEllipse.Stroke = Brushes.Black;
                myEllipse.Width = 4; myEllipse.Height = 4;
                Canvas.SetLeft(myEllipse, x - 2); Canvas.SetTop(myEllipse, y - 2);
                myEllipse.RenderTransform = panTransform;
                canvas1.Children.Add(myEllipse);
            }

            private Brush GetRandomShapeBrush()
            {
                int index = this.randBrush.Next() % this.shapeBrushes.Length;
                return this.shapeBrushes[index];
            }

            private void button_clear_Click(object sender, RoutedEventArgs e)
            {               
                OclSeedsPoint.Clear();              
                canvas1.Children.Clear();
                VorGraph = null;
            }
            // Delaunay Triangulation
            private void button_delaunay_Click(object sender, RoutedEventArgs e)
            {
                if (VorGraph == null) return;            
                //Debug.WriteLine("VorGraph.Edges:" + VorGraph.Edges.Count.ToString());
                foreach (BenTools.Mathematics.VoronoiEdge VorEdge in VorGraph.Edges)
                {
                    //imprimo los Edges
                    Line line = new Line();
                    line.Fill = Brushes.Blue;
                    line.StrokeThickness = 1;
                    line.Stroke = Brushes.Black;
                    line.X1 = VorEdge.LeftData[0];line.Y1 = VorEdge.LeftData[1];
                    line.X2 = VorEdge.RightData[0];line.Y2 = VorEdge.RightData[1];
                    //Debug.WriteLine("X1:" + line.X1.ToString() + " Y1:" + line.Y1.ToString());
                    //Debug.WriteLine("X2:" + line.X2.ToString() + " Y2:" + line.Y1.ToString());
                    line.RenderTransform = panTransform;
                    canvas1.Children.Add(line);
                }
            }

            private void button_export_svg_Click(object sender, RoutedEventArgs e)
            {

                if (LPolygon.Count < 1) return;

                // Storage all the poligon in a SVG file
                string now = DateTime.Now.ToString("dd-MM-yyyy HH mm ss");
                string filename = "Polygons_" + now + ".svg";
                System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo();
                nfi.NumberDecimalSeparator = ".";
                // defino un archivo para escribir
                System.IO.StreamWriter sw = new System.IO.StreamWriter(filename);

                sw.WriteLine("<svg xmlns=\"http://www.w3.org/2000/svg\"  height=\""+DrawHeight.ToString() +"pt\" width=\""+DrawWidth.ToString()+"pt\" version=\"1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">");

                // Write to file, the Polygon Collections
                 foreach (CLPolygon iPolygon in LPolygon)
                {
                    //sw.WriteLine("<polygon points=\"");
                    string points="";
                    if (iPolygon.PolPoints.Count > 0)
                    {
                        foreach (Point ipt in iPolygon.PolPoints)
                        {
                            points += Math.Round(ipt.X, 3).ToString(nfi) + "," + Math.Round(ipt.Y, 3).ToString(nfi) + " ";
                        }

                        // close 
                        sw.WriteLine("<polygon points=\"" + points + "\" style=\"fill:lime; stroke:black;stroke-width:1\" />");

                    }
                }
                sw.WriteLine("</svg>");// Enter              

                sw.Close();
            }

            private void button_export_acd_Click(object sender, RoutedEventArgs e)
            {
                if (LPolygon.Count < 1) return;
                // Storage all the poligon in a scr file
                string now = DateTime.Now.ToString("dd-MM-yyyy HH mm ss");
                string filename = "Polygons_" + now + ".scr";
                System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo();
                nfi.NumberDecimalSeparator = ".";
                // defino un archivo para escribir
                System.IO.StreamWriter sw = new System.IO.StreamWriter(filename);
                              

                // Write to file, the Polygon Collections
                foreach (CLPolygon iPolygon in LPolygon)
                {
                    Debug.WriteLine("LPolygon.Count:" + LPolygon.Count.ToString());
                   
                    if (iPolygon.PolPoints.Count > 0)
                    {
                        
                        sw.WriteLine("PLINE");

                        foreach (Point ipt in iPolygon.PolPoints)
                        {
                            sw.WriteLine(Math.Round(ipt.X, 3).ToString(nfi) + "," + Math.Round(ipt.Y, 3).ToString(nfi) );
                        }

                        // close 
                        sw.WriteLine("CLOSE");//sin espacios
                        

                    }
                }
                //sw.WriteLine("ZOOM E");// Enter              

                sw.Close();
            }

            private void button_MirrorH_Click(object sender, RoutedEventArgs e)
            {
                Tool = EClickedTool.MirrorH;
            }

            private void button_MirrorV_Click(object sender, RoutedEventArgs e)
            {
                Tool = EClickedTool.MirrorV;
            }

            private void button_MirrorFH_Click(object sender, RoutedEventArgs e)
            {
                Tool = EClickedTool.MirrorFH;
            }

            private void button_MirrorFV_Click(object sender, RoutedEventArgs e)
            {
                Tool = EClickedTool.MirrorFV;
            }

         
     
           

           

     

         
      

         
        }

    // Class to storage PntID,Edge
    public class CLEdgeData
    {
        public int PntId { get; set; }
        public Point A { get; set; }
        public Point B { get; set; }

        //public BenTools.Mathematics.VoronoiEdge VEdge { get; set; }
        //constructor
        public CLEdgeData(int argid, double Ax, double Ay, double Bx, double By)
        {
            PntId = argid;
            A = new Point(Ax, Ay);
            B = new Point(Bx, By);
        }

    }

    // Observable Collection of InpcPointData
    class OclPointData : ObservableCollection<InpcPointData>
    {
        private Random rnd= new Random();

        public void Random(double w,double h)
        {
          int sh=25,sw=25;            
            int Px = 0, Py = 0;
            double tiled = 0.8; //0.5 to 0.9
            for (int iy = 0; Py < (h); iy++)
            {
                for (int ix = 0; Px < (w); ix++)
                {
                    //Px = h * ix + iy % 2 *15;
                    //Py = w * iy + ix % 2 *15;
                    Px = sh * ix + (int)(sh * tiled * rnd.NextDouble()) ;
                    Py = sw * iy + (int)(sw * tiled * rnd.NextDouble());                                      
                    this.Add(new InpcPointData(Px, Py));                              
                    
                }
                Px = 0;
            }
        }
        public void Brick(double w, double h)
        {
            int sh = 25, sw = 25;
            int Px = 0, Py = 0;
            double tiled = 0.45; //0.4 more brick, 0.9 more random
            for (int iy = 0; Py < (h); iy++)
            {
                for (int ix = 0; Px < (w); ix++)
                {
                   // Px = (int)h * ix + iy % 2 * 15;
                   // Py = (int)w * iy + ix % 2 * 15;
                    Px = sh * ix + (int)(sh * tiled * rnd.NextDouble());
                    Py = sw * iy + (int)(sw * tiled * rnd.NextDouble());
                    this.Add(new InpcPointData(Px, Py));

                }
                Px = 0;
            }
        }

        public void Honey(double w, double h)
        {
            int sh = 30, sw = 30;
            int Px = 0, Py = 0;
            for (int iy = 0; Py < (h); iy++)
            {
                for (int ix = 0; Px < (w); ix++)
                {
                    Px = sh * ix + (iy % 2) * 15;
                    Py = sw * iy; // +iy % 2 * 5;
                    //Py = sw * iy +iy % 2 * 5;
                    this.Add(new InpcPointData(Px, Py));
                    
                }
                Px = 0;
            }

        }

        public void Circular(double w,double h)
        {
            double centerX = w / 2;
            double centerY = h / 2;
            double radio = 20 , pointcount= 18, alfa=0;

            this.Add(new InpcPointData(centerX , centerY));
            for (int circle= 1; circle < 20;circle ++)
            {
                for (int pn = 0; pn < pointcount; pn++)
                {
                    //Generate a point in polar coordinates
                    //alfa = Math.PI * 2 / pointcount * pn + circle% 2 * 0.2;// 360degrees/pointcount * pointnumber
                    alfa = Math.PI * 2 / pointcount * pn + Math.PI * 2 / pointcount* (circle % 2) *0.5;
                    //h = radio * circle - rnd.NextDouble() * 0.37 * radio ;
                    h = radio * circle;
                    //Debug.WriteLine("Rnd:"+h.ToString());                
                    this.Add(new InpcPointData(centerX + Math.Cos(alfa) * h, centerY + Math.Sin(alfa) * h));
                    

                }
            }
        
        }

        public void Spiral(double w, double h)
        {
            double centerX = w / 2;
            double centerY = h / 2;
            //this.Add(new InpcPointData(centerX, centerY));
            double radio = 10, pointcount = 200, alfa = 0;
           
                for (int pn = 0; pn < pointcount; pn++)
                {
                    //Generate a point in polar coordinates
                    this.Add(new InpcPointData(centerX + Math.Cos(alfa) * radio, centerY + Math.Sin(alfa) * radio));
                    alfa += Math.PI * 2 / 18;// 360/18 = Every 20 degrees                   
                    radio = pn* 1.5;
                }
        }
        public void SpiralDouble(double w, double h)
        {
            double centerX = w / 2;
            double centerY = h / 2;
            double degrees = 18;//18//15/10
            degrees = Math.PI * 2 /degrees;// 360/18 = Every 20 degrees 
            double alfa = 0, alfa2= degrees * 0.5;
            double radio = 15, pointcount = 150; 
            
            this.Add(new InpcPointData(centerX, centerY));
            for (int pn = 10; pn < pointcount; pn++)
            {
                //Generate a point in polar coordinates 
                alfa += degrees;
                alfa2 += degrees;
                Debug.WriteLine("alfa:" + alfa.ToString());
                Debug.WriteLine("alfa2:" + alfa2.ToString());   
                this.Add(new InpcPointData(centerX + Math.Cos(alfa) * radio, centerY + Math.Sin(alfa) * radio));
                this.Add(new InpcPointData(centerX - Math.Cos(alfa2) * radio, centerY - Math.Sin(alfa2) * radio));
              
                radio = pn * 1.75;
            }
        }
        public void LoadDemoRandom()
        {
            foreach (InpcPointData item in this)
            {
                item.X = 1;
                item.Y = 2;
            }
        }

        public void MirrorV(double w, double h, double Mx, double My)
        {
            OclPointData Result = new OclPointData();

            foreach (InpcPointData item in this)
            {
                if (item.X > Mx )
                {                   
                    continue;
                }
            

                Result.Add(item);
                double xx = 02 * Mx - item.X;
                double yy = item.Y;
                Result.Add(new InpcPointData ( xx,yy));
                
                //item.X = 1;
                //item.Y = 2;
            }

            // return Result;
            
            this.Clear();
             
            foreach (InpcPointData item in Result)

            {
                this.Add(item);
                
                }
            Result = null;
        }
    

    public void MirrorH(double w, double h, double Mx, double My)
        {
            OclPointData Result = new OclPointData();

            foreach (InpcPointData item in this)
            {
                if (item.Y > My )
                {                   
                    continue;
                }
            

                Result.Add(item);
                //double xx = 2 * Mx - item.X;
                //double yy = item.Y;
                double xx = item.X;
                double yy = 2 * My - item.Y;
               

                Result.Add(new InpcPointData ( xx,yy));
                
                //item.X = 1;
                //item.Y = 2;
            }

            // return Result;
            
            this.Clear();
             
            foreach (InpcPointData item in Result)

            {
                this.Add(item);
                
                }
            Result = null;
        }

    public void MirrorFlipH(double w, double h, double Mx, double My)
    {
        OclPointData Result = new OclPointData();

        foreach (InpcPointData item in this)
        {
            if (item.Y > My)
            {
                continue;
            }


            Result.Add(item);
            //double xx = 02 * Mx - item.X;
            //double yy = item.Y;  
            double xx =  Mx * 2 - item.X;
            double yy =  My * 2 - item.Y ;
          

            Result.Add(new InpcPointData(xx, yy));

            //item.X = 1;
            //item.Y = 2;
        }

        // return Result;

        this.Clear();

        foreach (InpcPointData item in Result)
        {
            this.Add(item);

        }
        Result = null;
    }
    public void MirrorFlipV(double w, double h, double Mx, double My)
    {
        OclPointData Result = new OclPointData();

        foreach (InpcPointData item in this)
        {
            if (item.X > Mx)
            {
                continue;
            }


            Result.Add(item);
            //double xx = 02 * Mx - item.X;
            //double yy = item.Y;
            double xx = Mx * 2 - item.X;
            double yy = My * 2 - item.Y;
       

            Result.Add(new InpcPointData(xx, yy));

            //item.X = 1;
            //item.Y = 2;
        }

        // return Result;

        this.Clear();

        foreach (InpcPointData item in Result)
        {
            this.Add(item);

        }
        Result = null;
    }
    
    }
     //--------------------------------
     // PointData
    //--------------------------------
    public class InpcPointData : INotifyPropertyChanged
    {        
        private double x; private double y;        
        public event PropertyChangedEventHandler PropertyChanged;
        
        protected void OnPropertyChanged(string info)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(info));
            }
        }
        public InpcPointData(double xx, double yy)
        {
            this.x = xx;this.y = yy;           
        }
        public double X
        {
            get { return x; } set {x = value;OnPropertyChanged("X");}
        }
        public double Y
        {
            get { return y; } set {y = value; OnPropertyChanged("Y");}
        }        
    }

    //--------------------------------------------
    // Storage Polygon data
    //--------------------------------------------
        public class CLPolygon
        {
            //public int PolId { get; set; }
            private List<Point> polpoints;

            public List<Point> PolPoints
            {
                get { return this.polpoints; }
                set { this.polpoints = value; } //from CLShapefile
            }
            /*/
            public CLPolygon(int argId, List<Point> argPolPoints) 
            {
                PolId = argId;
                PolPoints = argPolPoints;
            }
            */


            public  CLPolygon()
                {                    
                    PolPoints = new List<Point>();
                }

            public Point Center()
            {
                if (PolPoints.Count == 0) return new Point(0, 0);
                // calculate max and min x and y
                double minX = PolPoints[0].X;
                double maxX = PolPoints[0].X;
                double minY = PolPoints[0].Y;
                double maxY = PolPoints[0].Y;                

                foreach (Point ipoint in PolPoints) 
                {
                    if (ipoint.X < minX) minX = ipoint.X;
                    if (ipoint.X > maxX) maxX = ipoint.X;
                    if (ipoint.Y < minY) minY = ipoint.Y;
                    if (ipoint.Y > maxY) maxY = ipoint.Y;
                }

                return new Point(minX + (maxX - minX) / 2, minY + (maxY - minY) / 2);
            }

            // PolygonScale
            public  void PolygonScale(double scale)
            {
                Point center = this.Center();               
                for (int i = 0; i < polpoints.Count; i++)                 
                {
                    polpoints[i] = SegmentScale(center, polpoints[i], scale);
                }                
            }
            // Scale segment
            public Point SegmentScale(Point start, Point end, double scalar)
            {
                //double scalar = 0.5;
                double deltaX = (end.X - start.X) * scalar;
                double deltaY = (end.Y - start.Y) * scalar;
                return new Point(start.X + deltaX, start.Y + deltaY);
            }
	       
      

        }
}